import os
import sys
import time
import signal
import subprocess
import logging
import shutil
import re
from pathlib import Path
import json
import websocket
import threading
import psutil

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger('TWRPA')

# 全局变量存储进程和端口
processes = {
    'frontend': None,
    'backend': None,
    'chrome': None
}
frontend_port = 8080  # 默认端口

def find_chrome():
    """查找Chrome浏览器路径"""
    possible_paths = [
        os.path.join(os.environ.get('PROGRAMFILES', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'),
        os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'Google', 'Chrome', 'Application', 'chrome.exe'),
        os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Google', 'Chrome', 'Application', 'chrome.exe')
    ]
    
    for path in possible_paths:
        if os.path.exists(path):
            return path
    return None

def start_chrome():
    """启动Chrome浏览器并启用远程调试"""
    logger.info('正在启动Chrome浏览器...')
    try:
        chrome_path = find_chrome()
        if not chrome_path:
            logger.error('未找到Chrome浏览器')
            return None
            
        # 启动Chrome并启用远程调试
        chrome_process = subprocess.Popen(
            [
                chrome_path,
                '--remote-debugging-port=9222',
                '--user-data-dir=chrome-debug-profile',
                f'http://localhost:{frontend_port}'
            ],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            bufsize=1,
            universal_newlines=True
        )
        
        # 等待Chrome启动
        time.sleep(3)
        
        # 检查进程是否还在运行
        if chrome_process.poll() is not None:
            logger.error('Chrome浏览器启动失败')
            return None
            
        processes['chrome'] = chrome_process
        return chrome_process
    except Exception as e:
        logger.error(f'启动Chrome浏览器失败: {e}')
        return None

def find_nodejs():
    """查找Node.js安装路径"""
    # 常见的Node.js安装路径
    possible_paths = [
        os.path.join(os.environ.get('PROGRAMFILES', ''), 'nodejs'),
        os.path.join(os.environ.get('PROGRAMFILES(X86)', ''), 'nodejs'),
        os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Programs', 'nodejs'),
        os.path.join(os.environ.get('APPDATA', ''), 'npm'),
        os.path.join(os.environ.get('USERPROFILE', ''), 'AppData', 'Roaming', 'npm')
    ]
    
    # 检查环境变量PATH中的路径
    path_dirs = os.environ.get('PATH', '').split(os.pathsep)
    possible_paths.extend(path_dirs)
    
    # 查找node.exe
    for path in possible_paths:
        if not path:
            continue
        node_path = os.path.join(path, 'node.exe')
        if os.path.exists(node_path):
            return path
    
    return None

def check_nodejs():
    """检查Node.js环境"""
    logger.info('正在检查Node.js环境...')
    
    # 查找Node.js安装路径
    nodejs_path = find_nodejs()
    if not nodejs_path:
        logger.error('未找到Node.js，请先安装Node.js')
        logger.info('您可以从 https://nodejs.org/ 下载并安装Node.js')
        logger.info('安装完成后，请确保将Node.js添加到系统环境变量PATH中')
        sys.exit(1)
    
    logger.info(f'找到Node.js安装路径: {nodejs_path}')
    
    # 检查node命令
    try:
        node_version = subprocess.run(['node', '--version'], 
                                   capture_output=True, 
                                   text=True,
                                   shell=True).stdout.strip()
        logger.info(f'Node.js版本: {node_version}')
    except Exception as e:
        logger.error(f'检查Node.js版本失败: {e}')
        logger.info('请确保Node.js已正确安装并添加到系统环境变量PATH中')
        sys.exit(1)
    
    # 检查npm命令
    try:
        npm_version = subprocess.run(['npm', '--version'], 
                                  capture_output=True, 
                                  text=True,
                                  shell=True).stdout.strip()
        logger.info(f'npm版本: {npm_version}')
    except Exception as e:
        logger.error(f'检查npm版本失败: {e}')
        logger.info('请确保npm已正确安装并添加到系统环境变量PATH中')
        sys.exit(1)

def check_python_dependencies():
    """检查Python依赖"""
    logger.info('正在检查Python依赖...')
    try:
        subprocess.run([sys.executable, '-m', 'pip', 'install', '-r', 'requirements.txt'], check=True)
    except subprocess.CalledProcessError as e:
        logger.error(f'安装依赖失败: {e}')
        sys.exit(1)

def check_node_dependencies():
    """检查Node.js依赖"""
    logger.info('正在检查Node.js依赖...')
    try:
        # 确保前端目录存在
        if not os.path.exists('frontend'):
            logger.error('前端目录不存在')
            sys.exit(1)
            
        # 确保package.json存在
        if not os.path.exists('frontend/package.json'):
            logger.error('package.json文件不存在')
            sys.exit(1)
            
        # 安装依赖
        subprocess.run(['npm', 'install'], cwd='frontend', check=True, shell=True)
        logger.info('Node.js依赖安装完成')
    except subprocess.CalledProcessError as e:
        logger.error(f'安装前端依赖失败: {e}')
        sys.exit(1)
    except Exception as e:
        logger.error(f'检查Node.js依赖时发生错误: {e}')
        sys.exit(1)

def monitor_frontend_output(process):
    """监控前端输出并捕获端口"""
    global frontend_port
    start_time = time.time()
    timeout = 30  # 30秒超时
    
    while time.time() - start_time < timeout:
        if process.poll() is not None:
            return False
            
        # 读取输出
        output = process.stdout.readline()
        if output:
            output = output.strip()
            logger.info(f"Frontend: {output}")
            
            # 尝试匹配端口信息
            port_match = re.search(r'Local:\s+http://localhost:(\d+)', output)
            if port_match:
                frontend_port = int(port_match.group(1))
                logger.info(f"检测到前端服务端口: {frontend_port}")
                return True
                
        # 检查错误输出
        error = process.stderr.readline()
        if error:
            error = error.strip()
            logger.error(f"Frontend Error: {error}")
            
        time.sleep(0.1)
    
    return False

def start_frontend():
    """启动前端服务"""
    logger.info('正在启动前端服务...')
    try:
        # 确保在正确的目录
        if not os.path.exists('frontend'):
            logger.error('前端目录不存在')
            return None
            
        # 切换到前端目录
        os.chdir('frontend')
        
        # 使用subprocess.Popen启动前端服务
        frontend_process = subprocess.Popen(
            ['npm', 'run', 'serve'],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            bufsize=1,
            universal_newlines=True,
            shell=True
        )
        
        # 切回原目录
        os.chdir('..')
        
        # 监控前端输出并等待端口信息
        if not monitor_frontend_output(frontend_process):
            logger.error('前端服务启动失败或超时')
            frontend_process.terminate()
            return None
            
        processes['frontend'] = frontend_process
        return frontend_process
    except Exception as e:
        logger.error(f'启动前端服务失败: {e}')
        return None

def start_backend():
    """启动后端服务"""
    logger.info('正在启动后端服务...')
    try:
        # 确保后端目录存在
        if not os.path.exists('backend'):
            logger.error('后端目录不存在')
            return None
            
        # 确保app.py存在
        if not os.path.exists('backend/app.py'):
            logger.error('后端app.py文件不存在')
            return None
            
        # 确保数据目录存在
        os.makedirs(os.path.join('backend', 'data', 'processes'), exist_ok=True)
        
        # 使用subprocess.Popen启动后端服务
        backend_process = subprocess.Popen(
            [sys.executable, '.\\backend\\app.py'],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            bufsize=1,
            universal_newlines=True,
            shell=True
        )
        
        # 等待后端服务启动
        start_time = time.time()
        timeout = 30  # 30秒超时
        backend_started = False
        
        while time.time() - start_time < timeout:
            if backend_process.poll() is not None:
                logger.error('后端服务启动失败')
                return None
                
            # 读取输出
            output = backend_process.stdout.readline()
            if output:
                output = output.strip()
                logger.info(f"Backend: {output}")
                
                # 检查是否包含启动成功信息
                if 'Uvicorn running on' in output:
                    backend_started = True
                    logger.info('后端服务启动成功')
                    break
                    
            # 检查错误输出
            error = backend_process.stderr.readline()
            if error:
                error = error.strip()
                logger.error(f"Backend Error: {error}")
                
            time.sleep(0.1)
        
        if not backend_started:
            logger.error('后端服务启动超时')
            backend_process.terminate()
            return None
            
        processes['backend'] = backend_process
        return backend_process
    except Exception as e:
        logger.error(f'启动后端服务失败: {e}')
        return None

def monitor_processes():
    """监控进程状态"""
    while True:
        for name, process in processes.items():
            if process and process.poll() is not None:
                logger.error(f'{name}服务异常退出')
                return False
        time.sleep(1)
        return True

def cleanup():
    """清理进程"""
    logger.info('正在停止所有服务...')
    for name, process in processes.items():
        if process:
            try:
                if name == 'chrome':
                    # 查找并终止所有Chrome相关进程
                    for proc in psutil.process_iter(['pid', 'name']):
                        try:
                            if 'chrome' in proc.info['name'].lower():
                                proc.kill()
                        except (psutil.NoSuchProcess, psutil.AccessDenied):
                            pass
                else:
                    process.terminate()
                    process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                process.kill()
            except Exception as e:
                logger.error(f'停止{name}服务失败: {e}')

def signal_handler(signum, frame):
    """处理信号"""
    logger.info('收到停止信号，正在关闭服务...')
    cleanup()
    sys.exit(0)

def main():
    """主函数"""
    try:
        # 注册信号处理
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
        
        # 检查环境
        check_nodejs()
        
        # 检查依赖
        check_python_dependencies()
        check_node_dependencies()
        
        # 启动服务
        frontend_process = start_frontend()
        if not frontend_process:
            logger.error('前端服务启动失败')
            return
            
        backend_process = start_backend()
        if not backend_process:
            logger.error('后端服务启动失败')
            cleanup()
            return
            
        # 启动Chrome浏览器
        chrome_process = start_chrome()
        if not chrome_process:
            logger.warning('Chrome浏览器启动失败，继续运行其他服务')
            
        # 打印服务信息
        logger.info('=' * 50)
        logger.info('服务启动信息:')
        logger.info(f'前端访问地址: http://localhost:{frontend_port}')
        logger.info('后端API地址: http://127.0.0.1:8000')
        logger.info('API文档地址: http://127.0.0.1:8000/docs')
        logger.info('Chrome DevTools地址: http://localhost:9222')
        logger.info('按 Ctrl+C 停止所有服务')
        logger.info('=' * 50)
        
        # 监控进程
        while monitor_processes():
            time.sleep(1)
            
    except Exception as e:
        logger.error(f'启动服务失败: {e}')
        cleanup()
        sys.exit(1)

if __name__ == '__main__':
    main() 